package b649a01.poperators;

import java.util.Hashtable;
import java.util.StringTokenizer;

import b649a01.runners.sim_p;

/***
 * Integer branch calculator.
 * 
 * @author Chao Sun
 * @version 1.0
 */
public class branch extends calculator {
	private int t;
	private int s1;
	private int s2;
	// -2: already in table; -1: not in table and not found; N: index
	private int searchflag = -2;
	private boolean takeFlag = false;

	/**
	 * Constructor.
	 */
	public branch(sim_p sim, int i, int j, String op) {
		super(sim, i, j, op);
		Hashtable<String, Integer> cycleHash = simulator.getcycleHash();
		this.cycleNum = cycleHash.get(op);
		busyComUnit = "ADD";
	}

	/**
	 * Set locks to registers. Set computing unit lock.
	 * 
	 * @param opTokenizer
	 *          the string tokenizer containing all the operands
	 */
	@Override
	public void fetchRegs(StringTokenizer opTokenizer) {
		// add computing unit lock
		comUnitProperty.put("unit", busyComUnit);
		comUnitProperty.put("pipeIndex", pipelineIndex);
		simulator.addbusyComUnits(this, comUnitProperty);
		// get read register names and indexes
		source1 = opTokenizer.nextToken();
		s1Index = Integer.parseInt(source1.substring(1));
		readRegs.add(source1);
		// check if there is a second source
		if (operator.equals("BEQ") || operator.equals("BNEQ")) {
			source2 = opTokenizer.nextToken();
			s2Index = Integer.parseInt(source2.substring(1));
			readRegs.add(source2);
		}
		// update read registers, both local and in main processor
		readRegProperty.put("vector", readRegs);
		readRegProperty.put("pipeIndex", pipelineIndex);
		simulator.aadreadRegs(this, readRegProperty);
		// get branch label and index, assign index to t
		target = opTokenizer.nextToken();
		Hashtable<String, Integer> branchTable = simulator.getbranchTable();
		if (!branchTable.containsKey(target)) {
			searchflag = simulator.searchBranch(target);
		}
		if (searchflag == -2) {
			t = branchTable.get(target);
		} else if (searchflag == -1) {
			try {
				t = (int) (Integer.parseInt(target) / 32);
			} catch (NumberFormatException e) { // illegal branch label
				System.err.println("Branch label error!");
				finishFlag = true;
			}
		} else {
			t = searchflag;
		}
	}

	/**
	 * Assign values to registers unless there is RAW hazard. Remove read locks.
	 */
	@Override
	public void assignRegs() {
		R = simulator.getR();
		s1 = R[s1Index];
		if (source2 != null) {
			s2 = R[s2Index];
		}
		simulator.removereadRegs(readRegProperty);
		readRegs.clear();
	}

	/**
	 * Execute an arithmetic instruction. Remove computing unit lock.
	 */
	@Override
	public void execute() {
		if (!finishFlag) {
			if (operator.equals("BEQ")) {
				takeFlag = (s1 == s2);
			} else if (operator.equals("BNEQ")) {
				takeFlag = (s1 != s2);
			} else if (operator.equals("BGTZ")) {
				takeFlag = (s1 > 0);
			} else if (operator.equals("BLTZ")) {
				takeFlag = (s1 < 0);
			}
			finishFlag = true;
		}

		cycleNum--;
	}

	/**
	 * Write results back to memory or complete a branch.
	 */
	public void memory() {
		if (takeFlag) {
			simulator.setbranchFlag();
			simulator.setbranchIndex(t);
		}
		aliveFlag = false;
	}

}